package readconf

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"runtime"
)

type configuration map[string]string

var comment byte

var testconf configuration //全局变量

// Listener is an interface to monitor if the conf is changed
type Listener interface {
	listen(inifile string)
}

type ListenFunc func(string)

type Mylistener struct {
	F ListenFunc
}

func (methods Mylistener) listen(infile string) {
	methods.F(infile)
}

// Listen is true method which is used
func Mylisten(filename string) {
	newConf, err := GetConf(filename)
	if err != nil {
		os.Exit(1)
	}
	for key, value := range newConf {
		if _, ok := testconf[key]; !ok || testconf[key] != value {
			testconf = newConf
			fmt.Println("file has been changed")
			PrintConf(testconf)
			break
		}
	}
	return
}

//PrintConf is used to print a conf
func PrintConf(conf configuration) {
	for key, value := range conf {
		fmt.Printf("key: %s value: %s\n", key, value)
	}
}

// Init is used to determine the comment symbol in this os
func Init() {
	sys := runtime.GOOS
	if sys == "linux" {
		comment = '#'
	}
	if sys == "windows" {
		comment = ';'
	}
}

// GetConf gets a configuration
func GetConf(filename string) (configuration, error) {
	conf := make(configuration)
	var returnError error
	file, err := os.Open(filename)
	if err != nil {
		returnError = errors.New("Failed to open file")
		return conf, returnError
	}
	defer file.Close()
	buffer := bufio.NewReader(file)
	//ifBreak := false
	for {
		line, err := buffer.ReadString('\n')
		if err == io.EOF {
			break
		} else if err != nil {
			returnError = errors.New("error in read")
			break
		}
		if line == "" {
			continue
		} else if line[0] == comment {
			continue
		} else if line[0] == '[' && line[len(line)-2] == ']' {
			continue
		} else {
			var key string
			var value string
			for i := 0; i < len(line); i++ {
				if line[i] == '=' {
					key = line[:i-1]
					value = line[i+2 : len(line)-1]
					break
				}
			}
			conf[key] = value
		}
	}
	return conf, returnError
}

// Watch uses Listener
func Watch(filename string, listener Listener) (configuration, error) {
	var err error
	testconf, err = GetConf(filename)
	if err != nil {
		return nil, err
	}
	PrintConf(testconf)
	for {
		listener.listen(filename)
	}
	return testconf, nil
}